#include "thread_usage.h"
#include <mutex>
#include <exception>

void thread_set_promise(std::promise<int>& promiseObj) {
    std::cout << "In a thread, making data. wait for 10 seconds"<<std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    promiseObj.set_value(9);
    std::cout<<"end"<<std::endl;
}

void TestPromiseFutureBefore() {
    std::promise<int> promiseObj;
    std::future<int> futureObj = promiseObj.get_future();
    std::thread t(&thread_set_promise, std::ref(promiseObj));
    if (std::future_status::timeout == futureObj.wait_for(std::chrono::milliseconds(4000))){
        static uint32_t times = 0;
        times ++;
        std::cout<<"time out "<< times <<std::endl;
    }
    int ret = futureObj.get();
    std::cout<<"get value "<<ret<<std::endl;
    t.join();
}

void independentThread() {
    std::cout << "Starting concurrent thread.\n";
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Exiting concurrent thread.\n";
}

void TestThreadDetach() {
    std::cout << "Starting thread caller.\n";
    std::thread t(independentThread);
    // t.detach();
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "Exiting thread caller.\n";
    std::cout << "done.\n";
}
std::mutex gMtx;

void print_even (int x) {
  if (x%2==0) std::cout << x << " is even\n";
  else throw (std::logic_error("not even"));
}

void print_thread_id (int id) {
  try {
    // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
    std::lock_guard<std::mutex> lck (gMtx);
    print_even(id);
  }
  catch (std::logic_error& e ) {
    std::cout << "[exception caught]: ";
    std::cout<< e.what()<<std::endl;
  }
}

void TestLockGuard() {
    std::thread threads[10];
    // spawn 10 threads:`
    for (int i = 0; i < 10; ++i)
        threads[i] = std::thread(
            print_thread_id,i+1
        );

    for (auto& th : threads) 
        th.join();

    return ;
}

std::mutex cMtx; // 全局互斥锁.
std::condition_variable gCv; // 全局条件变量.
bool gReady = false; // 全局标志位.

void do_print_id(int id) {
    std::unique_lock <std::mutex> lck(cMtx);
    while (!gReady)
        gCv.wait(lck); // 当前线程被阻塞, 当全局标志位变为 true 之后,
    // 线程被唤醒, 继续往下执行打印线程编号id.
    std::cout << "thread " << id << '\n';
}

void go(){
    gReady = false;
    gCv.notify_all(); // 唤醒所有线程.
}

void go_once(){
    gReady = true;
    gCv.notify_one(); // 唤醒所有线程.
}

int TestConditionVariable() {
    std::thread threads[10];
    // spawn 10 threads:
    for (int i = 0; i < 10; ++i)
        threads[i] = std::thread(do_print_id, i);
    std::cout << "10 threads ready to race...\n";
    Sleep(1000);
    go_once();
    go_once();
    go_once();
    go_once();

    for (auto & th:threads)
        th.join();
    return 0;
}

class TestClass {
public:
    TestClass() : num(new int(0))
    {
        std::cout << "construct!" << std::endl;
    }
    //拷贝构造函数
    TestClass(const TestClass &d) : num(new int(*d.num))
    {
        std::cout << "copy construct!" << std::endl;
    }
    ~TestClass()
    {
        std::cout << "class destruct!" << std::endl;
    }

private:
    int *num;
};

TestClass get_demo() {
    return TestClass();
}

int TestOptiomization() {
    TestClass a = get_demo();
    return 0;
}


int TestRValue()  { 
    std::string str = "Hello";
    std::vector<std::string> v;
    //调用常规的拷贝构造函数，新建字符数组，拷贝数据
    v.push_back(str);
    std::cout << "After copy, str is \"" << str << "\"\n";
    //调用移动构造函数，掏空str，掏空后，最好不要使用str
    v.push_back(std::move(str));
    std::cout << "After move, str is \"" << str << "\"\n";
    std::cout << "The contents of the vector are \"" << v[0];
    return 0;
}

int global = 0;
class TestTask : public general::Task {
public:
    void Run()
    {
        auto t1 = std::chrono::steady_clock::now();
        std::string strValue = "{\"key\":\"value1\",\
            \"array\":[{\"arraykey\":1},{\"arraykey\":2}]}";   
            Json::Reader reader; 
            Json::Reader reader1; 
            Json::Reader reader2; 

            Json::Value root; 
            Json::Value root1; 
            Json::Value root2; 

        for (int i = 0;i <  10; i ++){
            reader.parse(strValue, root);
            reader1.parse(strValue, root1);
            reader2.parse(strValue, root2);
        }
        auto t2 = std::chrono::steady_clock::now();
        double dr_ms = std::chrono::duration<double,std::milli>(t2-t1).count();
        std::cout<<"expired is "<<dr_ms<<std::endl;             
    }
    void OnDone(){
        std::cout<<"the work is done"<<std::endl;
    }

};



// 42973.6
// 42942.3
int TestThreadPool() {
    //run code
    TestTask *t = new TestTask;
    general::ThreadPool pool(3);
    auto t1 = std::chrono::steady_clock::now();
    for(int i = 0;i < 10;i++){
        pool.AddTask(t);
    }    
    pool.Start();

    for(int i = 0;i < 20;i++){
        pool.AddTask(t);
    }

    pool.StopAll();
    auto t2 = std::chrono::steady_clock::now();
    double dr_ms = std::chrono::duration<double,std::milli>(t2-t1).count();
    std::cout<<"count is "<<dr_ms<<std::endl;
    getchar();
    return 0;
}


atomic<int> a{0};
atomic<int> b{0};
void ValueSet(int)
{
    a.store(0,memory_order_relaxed);
    b.store(0,memory_order_relaxed);

    for(int i = 0;i < 100;i++){
        int t=1;    
        a.store(t,memory_order_relaxed);
        b.store(2,memory_order_relaxed);
    }
}
void Observer(int)
{
    while(b.load(memory_order_relaxed)!=2);//自旋等待
    cout<<a.load(memory_order_relaxed)<<endl;
    cout<<"("<<a<<","<<b<<")"<<endl;//可能有多种输出

}

using namespace std;
std::atomic_llong total{ 0 };//原子数据类型
//int total{ 0 };
void func(int)
{
    for (long long i = 0; i<1000000000LL; ++i)
    {
        total += 1;
    }
}
void test_function(std::function<int(int)> t1) {
    t1(1);
}
int TestFuntionParadim() {
    
    return 0;
}
// 一个异步线程的封装
template<class Function,class Ret,class ... Args>
class ASyncProcess {
    public:
    ASyncProcess(Function t,Ret &ret,Args... args){
        std::cout<<"ASyncProcess construct"<<std::endl;
        mThread = new std::thread([this,t,&ret,args...](){
            try
            {
                ret = t(args...);
                this->m_finish = true;
            }
            catch(const std::exception& e)
            {
                std::cerr << e.what() << '\n';
            }
        });
    }
    ASyncProcess(Function t,Ret &ret){
        std::cout<<"ASyncProcess construct"<<std::endl;
        mThread = new std::thread([this,t,&ret](){
            ret = t();
            mMutex.lock();
            this->m_finish = true;
            mMutex.unlock();
        });
    }    
    bool Finish(){
        return m_finish;
    }
    virtual ~ASyncProcess() {
        mThread->detach();
    }
    private:
        bool m_finish = false;
        std::thread *mThread;
        std::mutex mMutex;
};

template<typename R, typename... Args>
int test2(R(&f)(Args...), R& ret_param, Args... args) {
    ret_param = f(args...);
    return 0;   
}

template<typename... Args>
int test2(void(&f)(Args...), Args... args)
{
    f(args...);
    return 0;   
}

int ss(int p,int w){
    return 1;
}

int main()
{
    int result =200;
    ASyncProcess<std::function<int(int)>,int,int> process([](int p) -> int{
        return 20;
    },result,150);
    while(process.Finish() == false) {

    }
    std::cout<<process.Finish() << "  "<<result<<"\r\n";
    getchar();
    std::cout<<process.Finish() << "  "<<result<<"\r\n";
}

